package com.lsb.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lsb.handler.JSONAuthentication;
import com.lsb.pojo.UserVerify;
import com.lsb.response.Result;
import com.lsb.response.ResultCode;
import com.lsb.utils.MyJsonUtils;
import com.lsb.utils.TencentCaptchaUtils;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author ：liusibo
 * @description：TODO
 * @date ：2021/6/10 0:10
 */
//自定义登录认证入口过滤器
public class MyLoginFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationManager authenticationManager;

    public MyLoginFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
        //设置该过滤器处理的url是/login接口，它是Spring Security的登录接口
        //表示该Filter拦截/login请求进行过滤操作
        super.setFilterProcessesUrl("/login");
    }

    // 接收并解析用户凭证(username和password)
    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
            throws AuthenticationException {
        //  登录入口，调用UserDetailsServiceImpl去实现账号密码登录
        try {
            System.out.println(req.getMethod());

            //读取request body中的params，获取表单的username和password
            // 获取腾讯防水墙的appid,randstr,ticket，用于后端验证图形验证码
            // 封装成UserVerify用户登录验证类,防水墙验证成功,再调用UserDetailsServiceImpl
            UserVerify user = new ObjectMapper()
                    .readValue(req.getInputStream(), UserVerify.class);

            //后端校验所需的参数
            String RAND_STR = user.getRandstr();
            String TICKET = user.getTicket();
            Long APP_ID = 2068453879L;
            String APP_SECRET = "0QnjIV2lbyN6lSxkVL5O7Mw**";
            String SECRET_ID = "AKIDkHZbMr52iOoyrUqvjGWUBbldEYcQxEEx";
            String SECRET_KEY = "TfZDagV4NQCgusZz92ez4sPgfOq1u97p";
            //调用api验证票据ticket和随机字符串randStr,若成功则是正常的从前端页面进行登录的,而不是恶意的脚本
            Result result = TencentCaptchaUtils.authenticationCaptcha(SECRET_ID,SECRET_KEY,APP_ID,APP_SECRET,TICKET,RAND_STR);
            System.out.println(result);
            //如果校验失败,则告知前端,图形验证错误,不可进行登录
            if((int)result.getData().get("code")!=1){
                try {
                    MyJsonUtils.WriteJSON(res,Result.error().message("校验失败"));
                    //直接返回null,不进行用户名和密码的校验了
                    return null;
                } catch (ServletException e) {
                    e.printStackTrace();
                }
            }


            //认证前，把用户名与密码封装在UsernamePasswordAuthenticationToken，它是实现了Authentication接口
            Authentication authRequest =
                    new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword());

            //AuthenticationManager会调用UserDetailsServiceImpl对封装的Authentication中的用户信息做认证
            //如果认证成功，则将UserDetailsServiceImpl返回的UserDetails再次封装成Authentication做返回
            return authenticationManager.authenticate(authRequest);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // 登录认证成功处理器
    @Override
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response,
                                            FilterChain chain,
                                            Authentication auth) throws IOException, ServletException {
        //在安全上下文context中添加用户认证信息Authentication
        SecurityContextHolder.getContext().setAuthentication(auth);
        String role = auth.getAuthorities().toString();
        //输出JSON返回给前端，表示登录成功，同时附带角色信息
        Result result = Result.ok().message("登录成功").data("role",role);
        new JSONAuthentication().WriteJSON(request,response,result);
    }

    // 登录认证失败处理器
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
        Result result = null;
        if (e instanceof AccountExpiredException) {
            //账号过期
            result = Result.error(ResultCode.USER_ACCOUNT_EXPIRED);
        } else if (e instanceof BadCredentialsException) {
            //密码错误
            result = Result.error(ResultCode.USER_CREDENTIALS_ERROR);
        } else if (e instanceof CredentialsExpiredException) {
            //密码过期
            result = Result.error(ResultCode.USER_CREDENTIALS_EXPIRED);
        } else if (e instanceof DisabledException) {
            //账号不可用
            result = Result.error(ResultCode.USER_ACCOUNT_DISABLE);
        } else if (e instanceof LockedException) {
            //账号锁定
            result = Result.error(ResultCode.USER_ACCOUNT_LOCKED);
        } else if (e instanceof InternalAuthenticationServiceException) {
            //用户不存在
            result = Result.error(ResultCode.USER_ACCOUNT_NOT_EXIST);
        }else{
            //其他错误
            result = Result.error(ResultCode.COMMON_FAIL);
        }
        /*//处理编码方式，防止中文乱码的情况
        response.setContentType("text/json;charset=utf-8");
        //塞到HttpServletResponse中返回给前台
        //这是springboot中jackson给我们提供的一种能将类或者其他对象转成json的方式
        response.getWriter().write(new ObjectMapper().writeValueAsString(result));*/

        //输出
        new JSONAuthentication().WriteJSON(request, response, result);
    }
}

